from queue import Empty
from loguru import logger
from protos import user_pb2,user_pb2_grpc
from models import AsyncSessionFactory
from models.user import User
from sqlalchemy.exc import IntegrityError
from sqlalchemy import update,select,delete,func
from google.protobuf import empty_pb2
from grpc import StatusCode
from utils.pwdutil import hash_password,check_password

class UserService(user_pb2_grpc.UserServicer):
    async def CreateUser(self, request:user_pb2.CreateUserRequest, context,session): # type: ignore
        mobile=request.mobile
        try:
            async with session.begin():
                user=User(mobile=mobile)
                session.add(user)
            response=user_pb2.UserInfoResponse(user_info=user.to_dict()) # type: ignore
            return response
        except IntegrityError as e:
            context.set_code(StatusCode.ALREADY_EXISTS)
            context.set_details('手机号已存在')
            
    async def UpdateAvatar(self,request:user_pb2.AvatarRequest,context,session):# type: ignore
        user_id=request.id
        avatar=request.avatar
        try:
            async with session.begin():
                stmt=update(User).where(User.id==user_id).values(avatar=avatar)
                result=await session.execute(stmt)
                if result.rowcount==0:
                    context.set_code(StatusCode.NOT_FOUND)
                    context.set_details('用户不存在')
                else:
                    return empty_pb2.Empty()
        except Exception as e:
            context.set_code(StatusCode.INTERNAL)
            context.set_details('更新失败')
            
    async def GetUserById(self,request:user_pb2.IdRequest,context,session): # type: ignore
        user_id=request.id
        try:
            async with session.begin():
                user=await session.get(User,user_id)
            response=user_pb2.UserInfoResponse(user_info=user.to_dict()) # type: ignore
            return response
        except Exception as e:
            context.set_code(StatusCode.INTERNAL)
            context.set_details('查询失败')
            
    async def GetUserByMobile(self,request:user_pb2.MobileRequest,context,session): # type: ignore
        mobile=request.mobile
        try:
            async with session.begin():
                user=await session.execute(select(User).where(User.mobile==mobile))
                user=user.scalar_one_or_none()
                if user:
                    return user_pb2.UserInfoResponse(user_info=user.to_dict()) # type: ignore
                else:
                    context.set_code(StatusCode.NOT_FOUND)
                    context.set_details('用户不存在')
        except Exception as e:
            context.set_code(StatusCode.INTERNAL)
            context.set_details('查询失败')
            
    async def UpdateUsername(self,request:user_pb2.UsernameRequest,context,session): # type: ignore
        user_id=request.id
        username=request.username
        try:
            async with session.begin():
                stmt=update(User).where(User.id==user_id).values(username=username)
                result=await session.execute(stmt)
                if result.rowcount==0:
                    context.set_code(StatusCode.NOT_FOUND)
                    context.set_details('用户不存在')
                else:
                    return empty_pb2.Empty()
        except Exception as e:
            context.set_code(StatusCode.INTERNAL)
            context.set_details('更新失败')
    
    async def UpdatePassword(self,request:user_pb2.PasswordRequest,context,session): # type: ignore
        user_id=request.id
        password=request.password
        new_password = hash_password(password)
        try:
            async with session.begin():
                stmt=update(User).where(User.id==user_id).values(password=new_password)
                result=await session.execute(stmt)
                if result.rowcount==0:
                    context.set_code(StatusCode.NOT_FOUND)
                    context.set_details('用户不存在')
                else:
                    return empty_pb2.Empty()
            return empty_pb2.Empty()
        except Exception as e:
            context.set_code(StatusCode.INTERNAL)
            context.set_details('更新失败')
            
    async def GetUserList(self,request:user_pb2.PageRequest,context,session): # type: ignore
        page=request.page
        page_size=request.page_size
        try:
            async with session.begin():
                query = await session.execute(select(User).limit(page_size).offset((page-1)*page_size))
                user_list = query.scalars().fetchall()
                user_list=[user.to_dict() for user in user_list]
                total = await session.execute(select(func.count(User.id)))
                total = total.scalar()
                if total is None:
                    total=0
            response=user_pb2.UserListResponse(user_list=user_list,total=total) # type: ignore
            return response
        except Exception as e:
            context.set_code(StatusCode.INTERNAL)
            context.set_details('查询失败')
    
    async def VerifyUser(self,request:user_pb2.VerifyUserRequest,context,session): # type: ignore
        mobile=request.mobile
        password=request.password
        try:
            async with session.begin():
                stmt=select(User).where(User.mobile==mobile)
                result=await session.execute(stmt)
                user=result.scalar_one_or_none()
                if user:
                    if check_password(password,user.password):
                        return user_pb2.UserInfoResponse(user_info=user.to_dict()) # type: ignore
                    else:
                        context.set_code(StatusCode.UNAUTHENTICATED)
                        context.set_details('密码错误')
                else:
                    context.set_code(StatusCode.NOT_FOUND)
                    context.set_details('用户不存在')
        except Exception as e:
            context.set_code(StatusCode.INTERNAL)
            context.set_details('查询失败')
            
    async def GetOrCreateUserByMobile(self,request:user_pb2.MobileRequest,context,session): # type: ignore
        mobile=request.mobile
        try:
            async with session.begin():
                stmt=select(User).where(User.mobile==mobile)
                result=await session.execute(stmt)
                user=result.scalar_one_or_none()
                if not user:
                    user = User(mobile=mobile)
                    session.add(user)
                    await session.flush()
            response= user_pb2.UserInfoResponse(user_info=user.to_dict())# type: ignore
            logger.info('收到！')      
            return response
        except Exception as e:
            context.set_code(StatusCode.INTERNAL)
            context.set_details('查询失败,用户没找到')
    
